#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高级图片垂直合并工具
将用户选择的多张图片垂直合并成一张图片，支持多种自定义选项
"""

import os
import sys
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, simpledialog
from PIL import Image, ImageDraw, ImageFont


class ImageMergerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("图片垂直合并工具")
        self.root.geometry("600x500")
        
        # 初始化变量
        self.image_paths = []
        self.preview_images = []
        
        # 创建界面
        self.create_widgets()
    
    def create_widgets(self):
        """创建界面组件"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 图片选择区域
        select_frame = ttk.LabelFrame(main_frame, text="图片选择", padding="5")
        select_frame.pack(fill=tk.X, pady=5)
        
        ttk.Button(select_frame, text="选择图片", command=self.select_images).pack(side=tk.LEFT, padx=5)
        ttk.Button(select_frame, text="清空列表", command=self.clear_images).pack(side=tk.LEFT, padx=5)
        self.count_label = ttk.Label(select_frame, text="已选择 0 张图片")
        self.count_label.pack(side=tk.LEFT, padx=20)
        
        # 图片列表
        list_frame = ttk.LabelFrame(main_frame, text="图片列表", padding="5")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 创建滚动条和列表框
        scrollbar = ttk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.image_listbox = tk.Listbox(list_frame, yscrollcommand=scrollbar.set)
        self.image_listbox.pack(fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.image_listbox.yview)
        
        # 合并选项区域
        options_frame = ttk.LabelFrame(main_frame, text="合并选项", padding="5")
        options_frame.pack(fill=tk.X, pady=5)
        
        # 对齐方式
        align_frame = ttk.Frame(options_frame)
        align_frame.pack(fill=tk.X, pady=2)
        ttk.Label(align_frame, text="对齐方式:").pack(side=tk.LEFT, padx=5)
        self.align_var = tk.StringVar(value="center")
        ttk.Radiobutton(align_frame, text="居中", variable=self.align_var, value="center").pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(align_frame, text="左对齐", variable=self.align_var, value="left").pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(align_frame, text="右对齐", variable=self.align_var, value="right").pack(side=tk.LEFT, padx=5)
        
        # 间距设置
        spacing_frame = ttk.Frame(options_frame)
        spacing_frame.pack(fill=tk.X, pady=2)
        ttk.Label(spacing_frame, text="图片间距:").pack(side=tk.LEFT, padx=5)
        self.spacing_var = tk.IntVar(value=0)
        ttk.Spinbox(spacing_frame, from_=0, to=50, textvariable=self.spacing_var, width=10).pack(side=tk.LEFT, padx=5)
        ttk.Label(spacing_frame, text="像素").pack(side=tk.LEFT)
        
        # 背景颜色
        bg_frame = ttk.Frame(options_frame)
        bg_frame.pack(fill=tk.X, pady=2)
        ttk.Label(bg_frame, text="背景颜色:").pack(side=tk.LEFT, padx=5)
        self.bg_color_var = tk.StringVar(value="white")
        color_options = ["white", "black", "gray", "lightgray", "darkgray", "red", "green", "blue"]
        self.bg_color_combo = ttk.Combobox(bg_frame, textvariable=self.bg_color_var, values=color_options, width=10)
        self.bg_color_combo.pack(side=tk.LEFT, padx=5)
        
        # 添加间隔线选项
        self.add_separator_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(options_frame, text="添加间隔线", variable=self.add_separator_var).pack(anchor=tk.W, pady=2)
        
        # 添加编号选项
        self.add_numbers_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(options_frame, text="添加图片编号", variable=self.add_numbers_var).pack(anchor=tk.W, pady=2)
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=10)
        
        ttk.Button(button_frame, text="预览效果", command=self.preview_merge).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="合并并保存", command=self.merge_and_save).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="退出", command=self.root.quit).pack(side=tk.RIGHT, padx=5)
    
    def select_images(self):
        """选择图片"""
        file_paths = filedialog.askopenfilenames(
            title="选择要合并的图片",
            filetypes=[
                ("图片文件", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_paths:
            self.image_paths = list(file_paths)
            self.update_image_list()
    
    def clear_images(self):
        """清空图片列表"""
        self.image_paths = []
        self.update_image_list()
    
    def update_image_list(self):
        """更新图片列表显示"""
        self.image_listbox.delete(0, tk.END)
        for i, path in enumerate(self.image_paths):
            filename = os.path.basename(path)
            try:
                with Image.open(path) as img:
                    width, height = img.size
                    self.image_listbox.insert(tk.END, f"{i+1}. {filename} ({width}x{height})")
            except:
                self.image_listbox.insert(tk.END, f"{i+1}. {filename} (无法读取)")
        
        self.count_label.config(text=f"已选择 {len(self.image_paths)} 张图片")
    
    def preview_merge(self):
        """预览合并效果"""
        if not self.image_paths:
            messagebox.showwarning("警告", "请先选择图片！")
            return
        
        # 创建预览窗口
        preview_window = tk.Toplevel(self.root)
        preview_window.title("合并预览")
        preview_window.geometry("800x600")
        
        # 创建画布
        canvas = tk.Canvas(preview_window, bg="gray")
        canvas.pack(fill=tk.BOTH, expand=True)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(preview_window, orient="vertical", command=canvas.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 创建预览图片
        try:
            merged_image = self.create_merged_image()
            
            # 调整预览大小
            canvas_width = 750
            canvas_height = 550
            img_width, img_height = merged_image.size
            
            # 计算缩放比例
            scale = min(canvas_width / img_width, canvas_height / img_height, 1.0)
            new_width = int(img_width * scale)
            new_height = int(img_height * scale)
            
            # 缩放图片
            preview_img = merged_image.resize((new_width, new_height), Image.LANCZOS)
            
            # 转换为Tkinter可显示的格式
            from PIL import ImageTk
            photo = ImageTk.PhotoImage(preview_img)
            
            # 在画布上显示图片
            canvas.create_image(canvas_width // 2, 10, anchor=tk.N, image=photo)
            canvas.configure(scrollregion=canvas.bbox("all"))
            
            # 保持引用防止被垃圾回收
            canvas.image = photo
            
        except Exception as e:
            canvas.create_text(400, 300, text=f"预览失败: {str(e)}", fill="white")
    
    def create_merged_image(self):
        """创建合并后的图片"""
        if not self.image_paths:
            raise ValueError("没有选择图片")
        
        # 打开所有图片
        images = []
        max_width = 0
        total_height = 0
        
        for img_path in self.image_paths:
            try:
                img = Image.open(img_path)
                images.append(img)
                
                # 计算最大宽度和总高度
                width, height = img.size
                max_width = max(max_width, width)
                total_height += height
                
                # 添加间距
                if self.spacing_var.get() > 0 and img != images[-1]:
                    total_height += self.spacing_var.get()
                    
            except Exception as e:
                raise ValueError(f"无法打开图片 {img_path}: {e}")
        
        # 添加间隔线的高度
        if self.add_separator_var.get():
            total_height += (len(images) - 1) * 2  # 每条线2像素
        
        # 创建新图片
        bg_color = self.bg_color_var.get()
        if bg_color == "white":
            bg_rgb = (255, 255, 255)
        elif bg_color == "black":
            bg_rgb = (0, 0, 0)
        elif bg_color == "gray":
            bg_rgb = (128, 128, 128)
        elif bg_color == "lightgray":
            bg_rgb = (200, 200, 200)
        elif bg_color == "darkgray":
            bg_rgb = (64, 64, 64)
        elif bg_color == "red":
            bg_rgb = (255, 0, 0)
        elif bg_color == "green":
            bg_rgb = (0, 255, 0)
        elif bg_color == "blue":
            bg_rgb = (0, 0, 255)
        else:
            bg_rgb = (255, 255, 255)  # 默认白色
        
        merged_image = Image.new('RGB', (max_width, total_height), bg_rgb)
        
        # 垂直合并图片
        y_offset = 0
        align = self.align_var.get()
        
        for i, img in enumerate(images):
            # 计算x偏移量
            width, height = img.size
            
            if align == "center":
                x_offset = (max_width - width) // 2
            elif align == "left":
                x_offset = 0
            elif align == "right":
                x_offset = max_width - width
            else:
                x_offset = (max_width - width) // 2  # 默认居中
            
            # 将图片粘贴到新图片上
            merged_image.paste(img, (x_offset, y_offset))
            
            # 添加编号
            if self.add_numbers_var.get():
                try:
                    # 尝试使用系统字体
                    font = ImageFont.truetype("arial.ttf", 20)
                except:
                    try:
                        # 尝试使用默认字体
                        font = ImageFont.load_default()
                    except:
                        font = None
                
                if font:
                    draw = ImageDraw.Draw(merged_image)
                    text = str(i + 1)
                    text_position = (x_offset + 10, y_offset + 10)
                    draw.text(text_position, text, fill=(255, 0, 0), font=font)
            
            y_offset += height
            
            # 添加间距
            if self.spacing_var.get() > 0 and i < len(images) - 1:
                y_offset += self.spacing_var.get()
            
            # 添加间隔线
            if self.add_separator_var.get() and i < len(images) - 1:
                draw = ImageDraw.Draw(merged_image)
                draw.line([(0, y_offset), (max_width, y_offset)], fill=(128, 128, 128), width=2)
                y_offset += 2
        
        # 关闭所有图片
        for img in images:
            img.close()
        
        return merged_image
    
    def merge_and_save(self):
        """合并并保存图片"""
        if not self.image_paths:
            messagebox.showwarning("警告", "请先选择图片！")
            return
        
        # 选择保存位置
        file_path = filedialog.asksaveasfilename(
            title="保存合并后的图片",
            defaultextension=".png",
            filetypes=[
                ("PNG图片", "*.png"),
                ("JPEG图片", "*.jpg"),
                ("所有文件", "*.*")
            ]
        )
        
        if not file_path:
            return
        
        try:
            # 创建合并图片
            merged_image = self.create_merged_image()
            
            # 保存图片
            merged_image.save(file_path)
            messagebox.showinfo("成功", f"图片已成功合并并保存到:\n{file_path}")
            
        except Exception as e:
            messagebox.showerror("错误", f"合并图片时出错:\n{str(e)}")


def main():
    """主函数"""
    root = tk.Tk()
    app = ImageMergerApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()